Galileo Computing < openbook > Galileo Computing - Professionelle Bücher. Auch für Einsteiger.

...powered by www.netzwerkartist.de...

Inhaltsverzeichnis
Vorwort
1 Java ist auch eine Sprache
2 Sprachbeschreibung
3 Klassen und Objekte
4 Der Umgang mit Zeichenketten
5 Mathematisches
6 Eigene Klassen schreiben
7 Exceptions
8 Die Funktionsbibliothek
9 Threads und nebenläufige Programmierung
10 Raum und Zeit
11 Datenstrukturen und Algorithmen
12 Dateien und Datenströme
13 Die eXtensible Markup Language (XML)
14 Grafische Oberflächen mit Swing
15 Grafikprogrammierung
16 Das Netz
17 JavaServer Pages und Servlets
18 Verteilte Programmierung mit RMI und Web–Services
19 Applets, Midlets und Sound
20 Datenbankmanagement mit JDBC
21 Reflection und Annotationen
22 Komponenten durch Bohnen
23 Logging und Monitoring
24 Sicherheitskonzepte
25 Java Native Interface (JNI)
26 Dienstprogramme für die Java-Umgebung
A Die Begleit-DVD
Index

Download:
- ZIP, ca. 12,5 MB
Buch bestellen

Website zum Buch
Weblog des Autors
Ihre Meinung?

Spacer
 <<   zurück
Java ist auch eine Insel von Christian Ullenboom
Programmieren mit der Java Standard Edition Version 6
Buch: Java ist auch eine Insel

Java ist auch eine Insel
6., akt. und erw. Aufl., mit DVD
1.454 S., 49,90 Euro
Galileo Computing
ISBN 3-89842-838-9
gp 8 Die Funktionsbibliothek
  gp 8.1 Die Java-Klassenphilosophie
    gp 8.1.1 Übersicht über die Pakete der Standardbibliothek
  gp 8.2 Wrapper-Klassen
    gp 8.2.1 Die Basisklasse Number für numerische Wrapper-Objekte
    gp 8.2.2 Die Klasse Integer
    gp 8.2.3 Unterschiedliche Ausgabeformate
    gp 8.2.4 Autoboxing: Boxing und Unboxing
    gp 8.2.5 Die Boolean-Klasse
    gp 8.2.6 Die Klassen Double und Float für Fließkommazahlen
  gp 8.3 Die Utility-Klasse System und Properties
    gp 8.3.1 Systemeigenschaften der Java-Umgebung
    gp 8.3.2 line.separator
    gp 8.3.3 Browser-Version abfragen
    gp 8.3.4 Property von der Konsole aus setzen
    gp 8.3.5 Umgebungsvariablen des Betriebssystems
    gp 8.3.6 Einfache Zeitmessung und Profiling
  gp 8.4 Benutzereinstellungen
    gp 8.4.1 Eine zentrale Registry
    gp 8.4.2 Einträge einfügen, auslesen und löschen
    gp 8.4.3 Auslesen der Daten und Schreiben in anderem Format
    gp 8.4.4 Auf Ereignisse horchen
  gp 8.5 Klassenlader (Class Loader)
    gp 8.5.1 Woher die kleinen Klassen kommen
    gp 8.5.2 Setzen des Klassenpfades
    gp 8.5.3 Die wichtigsten drei Typen von Klassenladern
    gp 8.5.4 Der java.lang.ClassLoader
    gp 8.5.5 Hot Deployment mit dem URL-ClassLoader
    gp 8.5.6 Das jre/lib/endorsed-Verzeichnis
    gp 8.5.7 getContextClassLoader() vom Thread
    gp 8.5.8 Wie heißt die Klasse mit der Methode main()?
  gp 8.6 Design-Pattern und das Beobachten von Änderungen
    gp 8.6.1 Design-Pattern
    gp 8.6.2 Das Beobachter-Pattern (Observer/Observable)
  gp 8.7 Ausführen externer Programme, Compiler und Skripten
    gp 8.7.1 ProcessBuilder und Prozesskontrolle mit Process
    gp 8.7.2 Die Windows-Registry verwenden
    gp 8.7.3 Einen Browser/E-Mail-Client/Editor aufrufen
    gp 8.7.4 Ausführen von Skripten
    gp 8.7.5 Programme mit der Compiler API übersetzen
  gp 8.8 Annotationen
    gp 8.8.1 Annotationstypen @Override, @Deprecated, @SuppressWarnings
    gp 8.8.2 Common Annotations
    gp 8.8.3 Annotationen für Web-Services
    gp 8.8.4 Annotationen für XML-Mapping
  gp 8.9 Zum Weiterlesen


Galileo Computing

8.2 Wrapper-Klassen  downtop

Wrapper-Klassen haben in der Java-Welt zwei wichtige Aufgaben:

  • Die Datenstrukturen, die in Java Verwendung finden, können nur Objekte aufnehmen. So stellt sich das Problem, wie primitive Datentypen zu diesen Containern hinzugefügt werden können. Die Klassenbibliothek bietet daher für jeden primitiven Datentyp eine entsprechende Wrapper-Klasse (auch »Ummantelungsklasse« oder »Envelope Class« genannt) an. Exemplare dieser Klassen kapseln je einen Wert des zugehörigen primitiven Typs.
  • Zusätzlich zu dieser Eigenschaft bieten die Wrapper-Klassen Funktionen zum Zugriff auf den Wert und einige Umwandlungsfunktionen.

Es existieren Wrapper-Klassen zu allen primitiven Datentypen.


Tabelle 8.2    Wrapper-Klassen und primitive Datentypen
Wrapper-Klasse Primitiver Typ
Byte byte
Short short
Integer int
Long long
Double double
Float float
Boolean boolean
Character char

Für void, was kein Datentyp ist, existiert die Klasse Void. Sie deklariert nur die Konstante TYPE vom Typ Class<Void> und ist für Reflection interessanter.

Erzeugen von Wrapper-Objekten

Objekte lieferten die Wrapper-Klassen auf zwei Arten: über Konstruktoren oder über statische valueOf()-Methoden. Übergeben werden die primitven Elemente oder auch Strings.


Beispiel Erzeuge einige Wrapper-Objekte:
Integer io = new Integer( 29 ); 
io = Integer.valueOf( 30 ); 
Long    lo = new Long( 0xC0B0L ); 
Double  do = new Double( 12.3 );


Hinweis Ist ein Wrapper-Objekt erst einmal erzeugt, kann der Wert nachträglich nicht mehr verändert werden. Um dies auch wirklich sicherzustellen, sind die konkreten Wrapper-Klassen allesamt final. Die Wrapper-Klassen sind nur als Ummantelung und nicht als vollständiger Datentyp gedacht. Da sich der Wert nicht mehr ändern lässt, heißen Objekte mit dieser Eigenschaft auch Werte-Objekte. Wollen wir den Inhalt eines Integer-Objekts io um eins erhöhen, so müssen wir Folgendes schreiben:
int i = 12; 
Integer io = new Integer( i ); 
io = new Integer( io.intValue() + 1 ); 
i = io.intValue();


Galileo Computing

8.2.1 Die Basisklasse Number für numerische Wrapper-Objekte  downtop

Die Wrapper-Klassen für byte, short, int, long, float und double sind Unterklassen der abstrakten Klasse Number. Daher implementieren die Klassen Byte, Short, Integer, Long, Float und Double und ebenfalls BigDecimal und BigInteger die abstrakten Methoden zur Umwandlung in einen speziellen Datentyp aus Number. In Java 5 kommen AtomicInteger und AtomicLong hinzu, die aber nicht immutable sind wie die anderen Klassen.

Die Methodennamen setzen sich aus den Namen des Basistyps und »Value« zusammen. Somit besitzen alle numerischen Wrapper-Klassen Methoden zur Umwandlung in die übrigen numerischen Datentypen.


abstract class java.lang.Number 
implements Serializable

  • byte byteValue() Liefert den Wert der Zahl als byte.
  • abstract double doubleValue() Liefert den Wert der Zahl als double.
  • abstract float floatValue() Liefert den Wert der Zahl als float.
  • abstract int intValue() Liefert den Wert der Zahl als int.
  • abstract long longValue() Liefert den Wert der Zahl als long.
  • short shortValue() Liefert den Wert der Zahl als short.

Nur die Methoden byteValue() und shortValue() sind nicht abstrakt und müssen nicht überschrieben werden. Diese Methoden rufen intValue() auf und konvertieren den Wert über eine Typanpassung auf byte und short.


Galileo Computing

8.2.2 Die Klasse Integer  downtop

Die Klasse Integer kapselt den Wert einer Ganzzahl vom Typ int in einem Objekt.

Eine Ganzzahl in einen String konvertieren

Die Umwandlung erfolgt mit der statischen toString()-Methode:

int number = 12345; 
String stringNumber = Integer.toString( number );

Zudem lässt sich auch mit der überladenen statischen Funktion String.valueOf() ein int in einen String konvertieren. (Doch nutzt valueOf() intern auch nur Integer.toString(i, 10).)

Ein Java-Idiom zur Konvertierung ist auch folgende Anweisung:

"" + number

Hinweis Bei der Darstellung von großen Zahlen bietet sich eine landestypische (länderspezifische) Formatierung an. Dafür gibt es die Klasse java.text.NumberFormat mit der Methode format(). Folgende Zeile gibt eine Zahl mit der Punkt-Trennung in 1000er-Blöcken aus:
int n = 100000; 
String s = NumberFormat.getInstance().format( n );

String in eine Ganzzahl umwandeln

Um aus dem String wieder eine Zahl zu machen, nutzen wir parseInt(), wie schon im String-Kapitel 4 beschrieben. Eine spezialisierte Methode für eine gegebene Basis ist parse-Int(String, int radix). Diese ist gut für Hexadezimalzahlen mit der Basis 16.

Einige Anwendungsfälle:


Tabelle 8.3    Beispiele für Integer.parseInt() mit unterschiedlichen Zahlenbasen
Konvertieraufruf Ergebnis
parseInt("0", 10) 0
parseInt("473", 10) 473
parseInt("-0", 10) 0
parseInt("-FF", 16) –255
parseInt("1100110", 2) 102
parseInt("2147483647", 10) 2147483647
parseInt("-2147483648", 10) –2147483648
parseInt("2147483648", 10) throws NumberFormatException
parseInt("99", 8) throws NumberFormatException
parseInt("Papa", 10) throws NumberFormatException
parseInt("Papa", 27) 500050


final class java.lang.Integer 
extends Number 
implements Comparable<Integer>

  • static int parseInt( String s ) Erzeugt aus der Zeichenkette die entsprechende Zahl. Die Basis ist 10.
  • static int parseInt( String s, int radix ) Erzeugt die Zahl mit der gegebenen Basis. parseInt() nutzt länderspezifische Tausendertrennzeichen nicht.

Galileo Computing

8.2.3 Unterschiedliche Ausgabeformate  downtop

Neben der toString()-Methode, die eine Zahl als String-Repräsentation im vertrauten Dezimalsystem ausgibt, gibt es noch vier weitere Varianten für die binäre, hexadezimale und oktale Darstellung sowie für die Darstellung einer beliebigen Basis. Die Methoden sind allerdings nicht in der Oberklasse Number deklariert, da nur die Klassen Integer und Long die Methoden implementieren. Alle folgenden Ausgabemethoden sind statisch.


final class Long | Integer 
extends Number 
implements Comparable<Long> | Comparable<Integer>, Serializable

  • static String toBinaryString( int | long i ) Erzeugt eine Binärrepräsentation (Basis 2) der vorzeichenlosen Zahl.
  • static String toOctalString( int | long i ) Erzeugt eine Oktalzahlrepräsentation (Basis 8) der vorzeichenlosen Zahl.
  • static String toHexString( int | long i ) Erzeugt eine Hexadezimalrepräsentation (Basis 16) der vorzeichenlosen Zahl.
  • static String toString( int | long i, int radix ) Erzeugt eine String-Repräsentation der Zahl zur angegebenen Basis.

Wir dürfen nicht vergessen, dass das Format der Übergabe int beziehungsweise long ist und nicht byte. Dies führt zu Ausgaben, die einkalkuliert werden müssen. Genauso werden führende Nullen grundsätzlich nicht mit ausgegeben.

Listing 8.1    ToHex.java

class ToHex 
{ 
  public static void main( String[] args ) 
  { 
    System.out.println( "15=" + Integer.toHexString(15) );   // 15=f 
    System.out.println( "16=" + Integer.toHexString(16) );   // 16=10 
    System.out.println( "127=" + Integer.toHexString(127) ); // 127=7f 
    System.out.println( "128=" + Integer.toHexString(128) ); // 128=80 
    System.out.println( "255=" + Integer.toHexString(255) ); // 255=ff 
    System.out.println( "256=" + Integer.toHexString(256) ); // 256=100 
    System.out.println( "-1=" + Integer.toHexString(-1) );   // -1=ffffffff 
  } 
}

Galileo Computing

8.2.4 Autoboxing: Boxing und Unboxing  downtop

Neu seit Java 5 ist das Autoboxing. [Das dürfte dann die erste Spracheigenschaft sein, die Java von C# übernimmt. Sonst hat C# ja fast alles von Java übernommen. ] Das bedeutet, dass primitive Datentypen und Wrapper-Objekte bei Bedarf ineinander umgewandelt werden. Ein Beispiel:

int i     = 4711; 
Integer j = i;        // steht für  j = Integer.valueOf(i)    (1) 
int k     = j;        // steht für  k = j.intValue()          (2)

Die Anweisung in (1) nennt sich Boxing und erstellt automatisch ein Wrapper-Objekt, sofern es nötig ist. Schreibweise (2) ist das Unboxing und steht für das Beziehen des Elements aus dem Wrapper-Objekt. Das bedeutet: Überall dort, wo der Compiler ein primitives Element erwartet, aber ein Wrapper-Objekt vorhanden ist, entnimmt er den Wert mit einer passenden xxxValue()-Methode aus dem Wrapper.

Der Compiler kann nur dann eine automatische Typanpassung vornehmen, wenn alles zusammenpasst. Sei inc() eine Funktion, die ein neues Integer-Objekt erstellt:

public static Integer inc( Integer i ) 
{ 
  return new Integer( i.intValue() + 1 ); 
}

Die Rückgabe können wir unterschiedlich nutzen:

Object  o1 = inc( 2 ); 
Integer i1 = inc( 2 ); 
int     i2 = inc( 2 ); 
int     i3 = (Integer) inc( 2 );

Alle vier Anweisungen lassen sich übersetzen und sind möglich, da der Compiler weiß, dass die Rückgabe ein Integer ist, was per Unboxing auf den eingebauten Datentyp int konvertiert werden kann. Wenn wir die Funktion ein wenig abändern, sodass sie Object statt Integer liefert, so funktioniert das Autoboxing nicht mehr:

Object  o1 = inc( 2 ); 
Integer i1 = inc( 2 );             // Compilerfehler! 
int     i2 = inc( 2 );             // Compilerfehler! 
int     i3 = (Integer) inc( 2 );

Am angenehmsten ist die Schreibweise dann, wenn etwa in Datenstrukturen primitive Elemente abgelegt werden sollen.

List l = new ArrayList(); 
l.add( Math.sin(Math.PI/4) );

Allerdings warnt der Compiler hier; er wünscht sich eine typisierte Liste, also

List<Double> l = new ArrayList<Double>();

Leider ist es so, dass der Typ der Liste tatsächlich mit dem Wrapper-Typ Double festgelegt werden muss und nicht mit dem Primitivtyp double. Aber vielleicht ändert sich das ja noch irgendwann .

Mehr Probleme als Lösungen?

Mit dem Autoboxing ist eine Reihe von Unregelmäßigkeiten verbunden, die der Programmierer beachten muss, um Fehler zu vermeiden. Eine davon hängt mit dem Unboxing zusammen, das der Compiler immer dann vornimmt, wenn ein Ausdruck einen primitiven Wert erwartet. Wenn kein primitives Element erwartet wird, wird auch kein Unboxing vorgenommen.

Listing 8.2    com/javatutor/insel/lang/Autoboxing.java, Teil 1

package com.javatutor.insel.lang; 
 
class Autoboxing 
{ 
  public static void main( String[] args ) 
  { 
    Integer i1 = new Integer( 1 ); 
    Integer i2 = new Integer( 1 ); 
 
    System.out.println( i1 >= i2 );   // true 
    System.out.println( i1 <= i2 );   // true 
    System.out.println( i1 == i2 );   // false

Der Vergleich mit == ist weiterhin ein Referenzvergleich, und es findet kein Unboxing auf primitive Werte statt, sodass es auf einen Vergleich von primitiven Werten hinausläuft. Daher muss bei zwei unterschiedlichen Integer-Objekten dieser Vergleich immer falsch sein. Das ist natürlich problematisch, da die alte mathematische Regel »aus i <= j und i >= j folgt automatisch i == j« nicht mehr gilt. Wenn es die unterschiedlichen Integer-Objekte für gleiche Werte nicht gäbe, bestünde auch das Problem nicht.

Die Probleme hören aber damit nicht auf. Sun hat versucht, das Problem mit dem == damit zu lösen, dass über Boxing gebildete Integer-Objekte einem Pool entstammen. Da jedoch nicht beliebig viele Objekte aus einem Pool kommen können, gilt die Gleichheit der über Boxing gebildeten Objekte nur in einem ausgewählten Wertebereich zwischen –128 und +127, also dem Wertebereich eines Bytes.

Listing 8.3    com/javatutor/insel/lang/Autoboxing.java, Teil 2

    Integer j1 = 2; 
    Integer j2 = 2; 
    System.out.println( j1 == j2 );   // true 
    Integer k1 = 127; 
    Integer k2 = 127; 
    System.out.println( k1 == k2 );   // true 
    Integer l1 = 128; 
    Integer l2 = 128; 
    System.out.println( l1 == l2 );   // false 
    Integer m1 = 1000; 
    Integer m2 = 1000; 
    System.out.println( m1 == m2 );   // false

Wir haben schon betont, dass auch bei Wrapper-Objekten der Vergleich mit == immer ein Referenz-Vergleich ist. Da 2 und 127 im Wertebereich zwischen –128 und +127 liegen, kommen die entsprechenden Integer-Objekte aus dem Pool. Das gilt für 128 und 1000 nicht; sie sind immer neue Objekte. Damit ergibt auch der ==-Vergleich false.

Es ist interessant zu wissen, was nun genau passiert, wenn Boxing eine Zahl in ein Wrapper-Objekt umwandelt. In diesem Moment wird nicht der Konstruktor aufgerufen, sondern die statische valueOf()-Funktion. Sie kümmert sich auch um das Pooling.

Listing 8.4    com/javatutor/insel/lang/Autoboxing.java, Teil 3

    Integer n1 = new Integer( 10 ); 
    Integer n2 = Integer.valueOf( 10 ); 
    Integer n3 = 10; 
    Integer n4 = 10; 
    System.out.println( n1 == n2 );   // false 
    System.out.println( n2 == n3 );   // true 
    System.out.println( n1 == n3 );   // false 
 
    System.out.println( n3 == n4 );   // true 
  } 
}

Abschlussfrage Welche Ausgabe kommt auf den Bildschirm? Ändert sich etwas, wenn i und j auf 1111 stehen?

Integer i = 1, j = 1; 
boolean b = (i <= j && j <= i && i != j); 
System.out.println( b );

Keine Konvertierung null zu 0

Beim Unboxing führt der Compiler bzw. die Laufzeitumgebung keine Konvertierung von null auf 0 durch. Mit anderen Worten: Bei der folgenden versuchten Zuweisung gibt es eine NullPointerException zur Laufzeit, aber keinen Compilerfehler.

int n = (Integer) null;    // java.lang.NullPointerException

Galileo Computing

8.2.5 Die Boolean-Klasse  downtop

Die Klasse Boolean kapselt den Datentyp boolean. Sie deklariert zwei Konstanten für die Werte true und false. Es sind Boolean-Objekte, die einmal den Zustand »wahr« und einmal den Zustand »falsch« kodieren.


final class java.lang.Boolean 
implements Serializable, Comparable<Boolean>

  • Boolean( boolean value )
  • Boolean( String s ) Erzeugt ein neues Boolean-Objekt.
  • final static Boolean FALSE
  • final static Boolean TRUE Konstanten für Wahrheitswerte. Dazu verwenden wir die statische Methode valueOf().
  • static Boolean valueOf( String str ) Parst den String und gibt Boolean.TRUE oder Boolean.FALSE zurück. Die Methode hat gegenüber dem Konstruktor Boolean(boolean) den Vorteil, dass sie immer das gleiche Wahr- oder Falsch-Objekt (Boolean.TRUE oder Boolean.FALSE) zurückgibt, anstatt neue Objekte zu erzeugen. Daher ist es selten nötig, den Konstruktor aufzurufen und neue Boolean-Objekte aufzubauen.
  • public static boolean parseBoolean( String s ) Parst den String und liefert entweder true oder false.

Der Konstruktor beziehungsweise valueOf() und parseBoolean() nehmen Strings entgegen, wobei die Groß-/Kleinschreibung unwichtig ist. Die Zeichenfolge muss nur entweder »true« oder »false« sein. So ergibt auch »tRuE« ein Boolean-Objekt mit dem Inhalt true.


Galileo Computing

8.2.6 Die Klassen Double und Float für Fließkommazahlen  toptop

Die Klassen Double und Float haben wie die anderen Wrapper-Klassen eine Doppelfunktionalität. Sie kapseln zum einen eine Fließkommazahl als Objekt und bieten statische Utility-Funktionen. Wir kommen im Kapitel 5 noch genauer auf die Funktionen zurück.



Ihr Kommentar

Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen.





 <<   zurück



Copyright © Galileo Press 2007
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Galileo Computing]

Galileo Press, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de